#ifndef __RCOCORE_BUFFER_H__
#define __RCOCORE_BUFFER_H__

namespace rco {

namespace buf
{
	enum BufferType{not_init, former_type, latter_type};
}

template <class FormerType, class LatterType>
class OverlapBuffer
{
	typedef OverlapBuffer<FormerType, LatterType> Self;
public:
	enum {buf_size = sizeof(FormerType) >= sizeof(LatterType) ? sizeof(FormerType) : sizeof(LatterType)};

	OverlapBuffer()
	{
		bUsed = false;
		bufType = buf::not_init;
		memset(buf, 0, sizeof(buf));
	}

	OverlapBuffer(const Self& other)
	{
		DeepCopy(other);
	}

	void DeepCopy(const Self& other)
	{
		if (other.GetType() == buf::former_type)
		{
			if (!IsUsed() || GetType() != buf::former_type)
				InitAsFormer();
			*InnerGetFormer() = *other.InnerGetFormer();
		}
		else
		{
			if (!IsUsed() || GetType() != buf::latter_type)
				InitAsLatter();
			*InnerGetLatter() = *other.InnerGetLatter();
		}
	}

	~OverlapBuffer()
	{
		Destroy();
	}
	
	FormerType& GetFormerBuffer()
	{
		if (IsMatch(buf::former_type))
		{
			return *InnerGetFormer();
		}
		else // crash
		{
			FormerType* to_crash = nullptr;
			return *to_crash;
		}
	}

	const FormerType& GetFormerBuffer() const
	{
		Self* _this = const_cast<Self*>(this);
		return _this->GetFormerBuffer();
	}

	LatterType& GetLatterBuffer()
	{
		if (IsMatch(buf::latter_type))
		{
			return *InnerGetLatter();
		}
		else // crash
		{
			LatterType* to_crash = nullptr;
			return *to_crash;
		}
	}

	const LatterType& GetLatterBuffer() const
	{
		Self* _this = const_cast<Self*>(this);
		return _this->GetLatterBuffer();
	}

	void InitAsFormer()
	{
		Destroy();
		new(InnerGetFormer()) FormerType();
		bUsed   = true;
		bufType = buf::former_type;
	}

	void InitAsLatter()
	{
		Destroy();
		new(InnerGetLatter()) LatterType();
		bUsed = true;
		bufType = buf::latter_type;
	}

	bool IsUsed() const
	{
		return bUsed;
	}

	buf::BufferType GetType() const
	{
		return bufType;
	}

	void Destroy()
	{
		if (bUsed)
		{
			if (bufType == buf::former_type)
				InnerGetFormer()->~FormerType();
			else if (bufType == buf::latter_type)
				InnerGetLatter()->~LatterType();

			bufType = buf::not_init;
			bUsed	= false;
		}
	}

	Self& operator=(const Self& other)
	{
		DeepCopy(other);
		return *this;
	}

	Self& operator=(const FormerType& other)
	{
		GetFormerBuffer() = other;
		return *this;
	}

	Self& operator=(const LatterType& other)
	{
		GetLatterBuffer() = other;
		return *this;
	}

	Self& operator=(const OverlapBuffer<LatterType, FormerType>& other)
	{
		if (other.IsUsed())
		{
			if (other.GetType() == buf::former_type)
				GetLatterBuffer() = other.GetFormerBuffer();
			else
				GetFormerBuffer() = other.GetLatterBuffer();
		}

		return *this
	}

	template<class OtherType>
	Self& operator=(const OverlapBuffer<FormerType, OtherType>& other)
	{
		if (other.IsMatch(buf::former_type))
			GetFormerBuffer() = other.GetFormerBuffer();

		return *this;
	}

	template<class OtherType>
	Self& operator=(const OverlapBuffer<OtherType, FormerType>& other)
	{
		if (other.IsMatch(buf::latter_type))
			GetFormerBuffer() = other.GetLatterBuffer();

		return *this;
	}

	template<class OtherType>
	Self& operator=(const OverlapBuffer<LatterType, OtherType>& other)
	{
		if (other.IsMatch(buf::former_type))
			GetLatterBuffer() = other.GetFormerBuffer();

		return *this;
	}

	template<class OtherType>
	Self& operator=(const OverlapBuffer<OtherType, LatterType>& other)
	{
		if (other.IsMatch(buf::latter_type))
			GetFormerBuffer() = other.GetLatterBuffer();

		return *this;
	}

	bool IsMatch(buf::BufferType type) const
	{
		return (IsUsed() && GetType() == type);
	}

	// it had better not call this
	void* GetLawBuffer()
	{
		return reinterpret_cast<void*>(buf);
	}

protected:
	FormerType* InnerGetFormer()
	{
		return reinterpret_cast<FormerType*>(buf);
	}

	LatterType* InnerGetLatter()
	{
		return reinterpret_cast<LatterType*>(buf);
	}

	const FormerType* InnerGetFormer() const
	{
		return reinterpret_cast<const FormerType*>(buf);
	}

	const LatterType* InnerGetLatter() const 
	{
		return reinterpret_cast<const LatterType*>(buf);
	}

	bool			bUsed;
	buf::BufferType bufType;
	char			buf[buf_size];
};

}

#endif // __RCOCORE_BUFFER_H__